package com.blankii.androidlibrary.lib.version

import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Environment
import androidx.core.content.FileProvider
import androidx.fragment.app.Fragment
import com.blankii.androidlibrary.exts.logd
import com.google.gson.Gson
import okhttp3.Call
import okhttp3.Callback
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import java.io.File
import java.io.FileNotFoundException
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream


/**
 * author: blankii
 * created on: 2024/3/28 10:07
 * description: 在fir.im平台寄存apk安装包，每次点击查询是否有最新版本，下载提示进度条并自动安装
 * //-------------code <使用时自动安装apk的话需要在app包-manifest 中添加> separate-------------
 * 第一项
 * <!--8.0安装需要的权限-->
 * <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
 * 第二项
 * <application>
 *          <provider
 *             android:name="androidx.core.content.FileProvider"
 *             android:authorities="${applicationId}.fileProvider"
 *             android:exported="false"
 *             android:grantUriPermissions="true">
 *             <meta-data
 *                 android:name="android.support.FILE_PROVIDER_PATHS"
 *                 android:resource="@xml/file_paths" />
 *         </provider>
 * </application>
 * 第三项
 * 在res-xml-添加file_paths.xml
 * <paths>
 *     <external-path
 *         name="external"
 *         path="." />
 *     <external-files-path
 *         name="external_files"
 *         path="." />
 *     <cache-path
 *         name="cache"
 *         path="." />
 *     <external-cache-path
 *         name="external_cache"
 *         path="." />
 *     <files-path
 *         name="files"
 *         path="." />
 * </paths>
 * //-------------code <> separate-------------
 * 其他引用：高版本自动安装apk  https://cloud.tencent.com/developer/article/1719282
 */
object VersionManager {
    private const val TAG: String = "VersionManager"
    private fun getUrl(projectId: String, apiToken: String): String {
        return "http://api.appmeta.cn/apps/latest/$projectId?api_token=$apiToken"
    }

    /**
     * 下载版本信息
     * @param fragment Fragment
     * @param projectId String 项目id
     * @param apiToken String 账号人id 默认blankii-id
     * @param downloadListener DownloadResultListener
     */
    fun download(
        fragment: Fragment,
        projectId: String,
        downloadListener: DownloadResultListener,
        apiToken: String = "8a8bdf07470a0889edcb13117eb767d8"
    ) {

        //取消在这里授权，出现bug在 mumu模拟器Android12 出现无法下载的问题
        val url = getUrl(projectId, apiToken)
        downloadResult(fragment, url, downloadListener)
//        if (VersionUtils.isAndroid11()) {
//            PermissionManager.requestManageExternalStoragePermission(fragment.requireActivity())
//        } else {
//            PermissionManager.requestPermissions(
//                fragment.requireActivity(), object : PermissionResultListener {
//                    override fun success() {
//
//                    }
//
//                    override fun failure() {
//                        downloadListener.onFail("读写文件授权失败")
//                    }
//
//                }, *arrayOf(
//                    Manifest.permission.READ_EXTERNAL_STORAGE,
//                    Manifest.permission.WRITE_EXTERNAL_STORAGE
//                )
//            )
//        }
    }


    private fun downloadResult(
        fragment: Fragment, url: String, downloadListener: DownloadResultListener
    ) {
        downloadListener.onStart()
        val requestBuild = Request.Builder().url("$url").method("GET", null).build()
        val call = OkHttpClient().newCall(requestBuild)
        call.enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                e.printStackTrace()
                downloadListener.onFail("下载失败:${e.toString()}")
            }

            override fun onResponse(call: Call, response: Response) {
                val versionResponseBody = Gson().fromJson(
                    response.getResponseStringValue(), ApkVersionResponseBody::class.java
                )
                versionResponseBody.toString().logd(TAG)
                downloadListener.onFinish(versionResponseBody)
            }
        })
    }

    /**
     * 获取response.body 的字符串内容，response.body().toString 打印的是对象
     * @receiver Response
     * @return String
     */
    private fun Response.getResponseStringValue(): String = this.body()!!.string()

    /**
     * 下载apk文件 可以显示进度条
     * @param context Context
     * @param url String apk下载链接
     * @param savePath String 安卓存储路径
     * @param apkName String  下载的apk文件名称，需要后尾带.apk
     * @param downloadListener DownloadFileListener
     */
    fun downloadApk(
        context: Context,
        url: String,
        savePath: String,
        apkName: String,
        downloadListener: DownloadFileListener
    ) {
        if (!apkName.contains(".apk")) throw Exception("apkName 命名不合法，必须要带.apk")
        downloadListener.onStart()
        val requestBuild = Request.Builder().url("$url").method("GET", null).build()
//        val client = ProgressManager.getInstance().with(OkHttpClient.Builder())
//            .build()
        val client = OkHttpClient.Builder().addNetworkInterceptor {
            val originalResponse: Response = it.proceed(it.request())
            originalResponse.body() ?: throw java.lang.Exception("originalResponse.body is null")
            originalResponse.newBuilder()
                .body(ProgressResponseBody(originalResponse.body(), object : ProgressListener {
                    override fun update(bytesRead: Long, contentLength: Long, done: Boolean) {
//                        downloadListenr.onProgress(bytesRead, contentLength)
//                        "$bytesRead,$contentLength,$done".loge(TAG)
                    }
                })).build()
        }.build()
        val call = client.newCall(requestBuild)

        call.enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                //子线程
                downloadListener.onFail("下载失败:${e}")
            }

            override fun onResponse(call: Call, response: Response) {
                //子线程
                packResponse(context, response, savePath, apkName, downloadListener)
            }
        })
    }

    private fun packResponse(
        context: Context,
        response: Response,
        savePath: String,
        apkName: String,
        downloadListener: DownloadFileListener
    ) {

        var inputSteam: InputStream? = null
        val buf = ByteArray(2048)
        var len = 0
        var fos: FileOutputStream? = null
        // 储存下载文件的目录
        val savePath: String = isExistDir(savePath)
        var file: File? = null
        try {
            inputSteam = response.body()!!.byteStream()
            val total = response.body()!!.contentLength()
            file = File(savePath, apkName)
            "apk存储路径:${file.absolutePath}".logd(TAG)
//            Log.e("savePath", file.absolutePath)
            fos = FileOutputStream(file)
            var sum: Long = 0
            while (inputSteam.read(buf).also { len = it } != -1) {
                fos.write(buf, 0, len)
                sum += len.toLong()
                val progress = (sum * 1.0f / total * 100).toInt()
                // 下载中
                downloadListener.onProgress(progress)
            }
            fos.flush()
            // 下载完成
            downloadListener.onFinish()
        } catch (e: Exception) {
            downloadListener.onFail(e.toString())
        } finally {
            try {
                inputSteam?.close()
                fos?.close()
                install(context, file!!, downloadListener)
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
    }

    private fun isExistDir(savePath: String): String {
        // 下载位置
        if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED) {
            //外部存储可用
            val downloadFile = File(savePath)
            if (!downloadFile.mkdirs()) {
                downloadFile.createNewFile()
            }
            return downloadFile.absolutePath
        } else {
            //外部存储不可用
            throw FileNotFoundException("外部存储不可用")
        }
    }

    /**
     * 安装完apk，自动删除
     */
    private fun install(context: Context, apkFile: File, downloadListener: DownloadFileListener) {
        var uri: Uri? = null
        try { //这里有文件流的读写，需要处理一下异常
            val intent = Intent(Intent.ACTION_VIEW)
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
            uri = getUriForFile(context, apkFile)
            intent.setDataAndType(uri, "application/vnd.android.package-archive")
            context.startActivity(intent)
        } catch (e: java.lang.Exception) {
            e.printStackTrace()
            downloadListener.onFail("安装失败:$e")
        }
    }

    private fun getUriForFile(context: Context?, file: File?): Uri? {
        if (context == null || file == null) {
            throw NullPointerException()
        }
        val uri: Uri = if (Build.VERSION.SDK_INT >= 24) {
            FileProvider.getUriForFile(
                context.applicationContext, context.packageName + ".fileProvider", file
            )
        } else {
            Uri.fromFile(file)
        }
        return uri
    }

    /**
     * remoteVersion>localVersion   返回true 可以更新程序
     */
    fun compareVersions(localVersion: String, remoteVersion: String): Boolean {
        val lArr = Array(5) { 0 }
        val rArr = Array(5) { 0 }
        val la = localVersion.split(".")
        val ra = remoteVersion.split(".")
        for (i in la.indices) {
            lArr[i] = la[i].toInt()
        }
        for (i in ra.indices) {
            rArr[i] = ra[i].toInt()
        }
//        System.arraycopy(la,0,lArr,0,la.size)
//        System.arraycopy(ra,0,rArr,0,ra.size)
        for (i in lArr.indices) {
            if (rArr[i] > lArr[i]) {
                return true
            } else if (rArr[i] < lArr[i]) {
                return false
            } else {
                continue
            }
        }
//        if (rArr[0].toInt() > lArr[0].toInt()) {
//            return true
//        }else if(rArr[0].toInt() <lArr[0].toInt()){
//            return false
//        }
//            if (rArr[1].toInt() > lArr[1].toInt()) {
//            return true
//        } else if(){
//
//        } if (lArr.size == 3 && rArr.size == 3 && rArr[2].toInt() > lArr[2].toInt()) {
//            return true
//        }
       return false
    }
}